#include "qemu/osdep.h"
#include "qemu/module.h"
#include "hw/i2c/i2c.h"
#include "migration/vmstate.h"
#include "hw/qdev-properties.h"
#include "hw/qdev-properties-system.h"
#include "qapi/visitor.h"
#include "trace.h"
#include "chardev/char-fe.h"
#include "hw/misc/cJSON.h"


#define TYPE_MCU_I2CSLAVE "mcu-i2c-slave"
#define MCU_I2CSLAVE(obj) OBJECT_CHECK(slave_state, (obj), TYPE_MCU_I2CSLAVE)
#define I2C_PATH "./output/data/mockdata/i2c/"
#define SMBUS_MAX_BYTE 256
#define JSON_BUF_LEN 10 * 1000

static int WRITE_BUFFER_FLAG = 32;
static int READ_FLAG = 33;
static int WRITE_DATA_FLAG = 34;
static int MCU_ADDR = 200;
static int RSP_HEAD_LEN = 13;

enum {
    COMP_SUCCESS    = 0x0000,
    COMP_OPCODE_ERR = 0x0001,
    COMP_PARAM_ERR  = 0x0002,
    COMP_INNER_ERR  = 0x0003
};

typedef struct {
    I2CSlave parent_obj;
    CharBackend chrbe;
    uint32_t count_tx;
    uint32_t count_rx;
    char *path;
    char *key;
    uint8_t msg[SMBUS_MAX_BYTE];       // 通过key值获取的value
    char buffer[JSON_BUF_LEN];    // json文件所有内容
    FILE *p;
    bool write_flag;
    bool transfer_start;
    bool transfer_recv;
    uint8_t reg_id;
    uint16_t opcode;
    uint32_t offset;
    uint32_t data_length;
    uint32_t data_len_range;
    bool buffer_flag;   // 缓存是否需要修改的标志
    uint8_t data[SMBUS_MAX_BYTE]; // 应用层传下来的值
    uint8_t mock_data[SMBUS_MAX_BYTE]; // 需要返回给应用层的值
    time_t last_modify;
    struct stat file_stat;
} slave_state;

static int mcu_i2cslave_event(I2CSlave *i2c, enum i2c_event event)
{
    slave_state *s = MCU_I2CSLAVE(i2c);
    switch (event) {
        case I2C_START_SEND:
            if (s->path == NULL) {
                s->path = g_strdup_printf("%s%d/0xc8_mcu.json", I2C_PATH, s->reg_id);
            }            
            if (stat(s->path, &s->file_stat) != 0) {
                error_report("get mcu mock file(%s) stat failed\n", s->path);
            } else if (s->file_stat.st_mtime != s->last_modify) {
                warn_report("Detect %s changed, Reload buffer\n", s->path);
                s->buffer_flag = false;
                s->last_modify = s->file_stat.st_mtime;
            }
            s->transfer_start = true;
            s->transfer_recv = true;
            s->write_flag = false;
            s->count_tx = 0;
            s->count_rx = 0;
            s->opcode = 0;
            break;
        case I2C_START_RECV:
            s->transfer_start = true;
            s->transfer_recv = false;
            break;
        case I2C_FINISH:
            s->transfer_start = false;
            s->write_flag = true;
            s->count_tx = 0;
            break;
        case I2C_NACK:
            break;
    }
    return 0;
}

static uint8_t calc_crc(uint8_t *data, uint8_t byte_count)
{
    uint8_t crc_table[256] = {
        0x00, 0x07, 0x0E, 0x09, 0x1C, 0x1B, 0x12, 0x15, 0x38, 0x3F, 0x36, 0x31, 0x24, 0x23, 0x2A, 0x2D,
        0x70, 0x77, 0x7E, 0x79, 0x6C, 0x6B, 0x62, 0x65, 0x48, 0x4F, 0x46, 0x41, 0x54, 0x53, 0x5A, 0x5D,
        0xE0, 0xE7, 0xEE, 0xE9, 0xFC, 0xFB, 0xF2, 0xF5, 0xD8, 0xDF, 0xD6, 0xD1, 0xC4, 0xC3, 0xCA, 0xCD,
        0x90, 0x97, 0x9E, 0x99, 0x8C, 0x8B, 0x82, 0x85, 0xA8, 0xAF, 0xA6, 0xA1, 0xB4, 0xB3, 0xBA, 0xBD,
        0xC7, 0xC0, 0xC9, 0xCE, 0xDB, 0xDC, 0xD5, 0xD2, 0xFF, 0xF8, 0xF1, 0xF6, 0xE3, 0xE4, 0xED, 0xEA,
        0xB7, 0xB0, 0xB9, 0xBE, 0xAB, 0xAC, 0xA5, 0xA2, 0x8F, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9D, 0x9A,
        0x27, 0x20, 0x29, 0x2E, 0x3B, 0x3C, 0x35, 0x32, 0x1F, 0x18, 0x11, 0x16, 0x03, 0x04, 0x0D, 0x0A,
        0x57, 0x50, 0x59, 0x5E, 0x4B, 0x4C, 0x45, 0x42, 0x6F, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7D, 0x7A,
        0x89, 0x8E, 0x87, 0x80, 0x95, 0x92, 0x9B, 0x9C, 0xB1, 0xB6, 0xBF, 0xB8, 0xAD, 0xAA, 0xA3, 0xA4,
        0xF9, 0xFE, 0xF7, 0xF0, 0xE5, 0xE2, 0xEB, 0xEC, 0xC1, 0xC6, 0xCF, 0xC8, 0xDD, 0xDA, 0xD3, 0xD4,
        0x69, 0x6E, 0x67, 0x60, 0x75, 0x72, 0x7B, 0x7C, 0x51, 0x56, 0x5F, 0x58, 0x4D, 0x4A, 0x43, 0x44,
        0x19, 0x1E, 0x17, 0x10, 0x05, 0x02, 0x0B, 0x0C, 0x21, 0x26, 0x2F, 0x28, 0x3D, 0x3A, 0x33, 0x34,
        0x4E, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5C, 0x5B, 0x76, 0x71, 0x78, 0x7F, 0x6A, 0x6D, 0x64, 0x63,
        0x3E, 0x39, 0x30, 0x37, 0x22, 0x25, 0x2C, 0x2B, 0x06, 0x01, 0x08, 0x0F, 0x1A, 0x1D, 0x14, 0x13,
        0xAE, 0xA9, 0xA0, 0xA7, 0xB2, 0xB5, 0xBC, 0xBB, 0x96, 0x91, 0x98, 0x9F, 0x8A, 0x8D, 0x84, 0x83,
        0xDE, 0xD9, 0xD0, 0xD7, 0xC2, 0xC5, 0xCC, 0xCB, 0xE6, 0xE1, 0xE8, 0xEF, 0xFA, 0xFD, 0xF4, 0xF3};
    uint8_t crc = 0;
    for (int i = 0; i < byte_count; i++) {
        uint8_t index = data[i] ^ crc;
        crc = crc_table[index];
    }
    return crc;
}

static int change_json_buffer(slave_state *s)
{
    char ch_str[3] = {0};
    int json_index = 6;
    int data_index = RSP_HEAD_LEN;
    // 写操作msg第4,5字节为待写入的命令字
    char *changed_opcode = g_strdup_printf("0x%04x", (s->msg[4] << 8) + s->msg[5]);
    cJSON *root = cJSON_Parse(s->buffer);
    if (root == NULL) {
        error_report("parse mcu mock data json error\n");
        return COMP_INNER_ERR;
    }
    cJSON *value = cJSON_GetObjectItem(root, changed_opcode);
    if (value == NULL) {
        error_report("the key is error\n");
        return COMP_INNER_ERR;
    }
    int data_len = cJSON_GetArraySize(value);
    // 数组长度:1字节写标志+1字节数据长度校验+4字节数据总长+mock_data
    if (s->data_length > data_len - 6) {
        return COMP_INNER_ERR;
    }
    for (int i = 0; i < s->data_length; i++) {
        snprintf(ch_str, 3, "%02x", s->data[data_index]);
        cJSON_ReplaceItemInArray(value, json_index, cJSON_CreateString(ch_str));
        json_index++;
        data_index++;
    }
    char *new_json_str = cJSON_Print(root);
    s->p = fopen(s->path, "w+");
    if (s->p == NULL) {
        error_report("i2c%d open mcu file failed\n", s->reg_id);
        return COMP_INNER_ERR;
    }
    int ret = fwrite(new_json_str, strlen(new_json_str), 1, s->p);
    if (ret == 0) {
        ret = fclose(s->p);
        error_report("i2c%d write mcu file failed\n", s->reg_id);
        return COMP_INNER_ERR;
    }
    fclose(s->p);
    cJSON_Delete(root);
    return COMP_SUCCESS;
}

static uint16_t write_buffer(slave_state *s)
{
    s->p = fopen(s->path, "r+");
    if (s->p == NULL) {
        error_report("line : %d, i2c%d open mcu file failed\n", __LINE__, s->reg_id);
        return COMP_PARAM_ERR;
    }
    int ret = fseek(s->p, 0, SEEK_END);
    if (ret != 0) {
        goto err;
    }
    int file_size = ftell(s->p);
    if (file_size > JSON_BUF_LEN) {
        goto err;
    }
    ret = fseek(s->p, 0, SEEK_SET);
    if (ret != 0) {
        goto err;
    }
    
    ret = fread(s->buffer, sizeof(char), file_size, s->p);
    if (ret == 0) {
        goto err;
    }
    fclose(s->p);
    s->buffer_flag = true;
    return COMP_SUCCESS;

err:
    warn_report("i2c%d write mcu buffer failed\n", s->reg_id);
    fclose(s->p);
    return COMP_PARAM_ERR;
}

static uint8_t cjson_read_buffer_data(slave_state *s)
{
    cJSON *root = cJSON_Parse(s->buffer);
    if (root == NULL) {
        error_report("parse error\n");
        return COMP_INNER_ERR;
    }
    cJSON *value = cJSON_GetObjectItem(root, s->key);
    if (value == NULL || !cJSON_IsArray(value)) {
        cJSON_Delete(root);
        return COMP_OPCODE_ERR;
    }
    memset(s->msg, 0, sizeof(s->msg));
    int buffer_len = cJSON_GetArraySize(value);
    cJSON *item;
    // mock_data数组前2位分别为读写标志,长度校验
    item = cJSON_GetArrayItem(value, 0);
    s->write_flag = (cJSON_GetNumberValue(item) == 1) ? true : false;
    item = cJSON_GetArrayItem(value, 1);
    s->data_len_range = cJSON_GetNumberValue(item);    
    for (int i = 0; i < buffer_len - 2; i++) {
        // mock数据从第2字节开始
        item = cJSON_GetArrayItem(value, i + 2);
        if (item && cJSON_IsString(item)) {
            s->msg[i] = (uint8_t)strtol(item->valuestring, NULL, 16);
        } else {
            warn_report("Invalid array item at index: %d\n", i);
            s->msg[i] = 0x00;
        }
    }
    cJSON_Delete(root);
    return COMP_SUCCESS;
}

static uint8_t mcu_i2cslave_rx(I2CSlave *i2c)
{
    slave_state *s = MCU_I2CSLAVE(i2c);
    int rx = s->mock_data[s->count_rx];
    
    // 不足请求长度的数据填充0xff
    if (s->count_rx > s->mock_data[0]) {
        return 0xff;
    }

    s->count_rx++;
    return rx;
}

static uint8_t check_data_byte(slave_state *s)
{
    // LUN, para不校验
    uint8_t crc_calc_len = s->data[0] + 1;
    uint8_t req_crc_verify[256] = {MCU_ADDR, WRITE_BUFFER_FLAG};
    uint8_t crc_code = s->data[crc_calc_len];
    uint8_t crc_result;
    // 4字节小端offset,data_length
    s->offset = (s->data[8] << 24) + (s->data[7] << 16) + (s->data[6] << 8) + s->data[5];
    s->data_length = (s->data[12] << 24) + (s->data[11] << 16) + (s->data[10] << 8) + s->data[9];
    // 校验入参长度
    if (s->data_length != s->data_len_range) {
        return COMP_PARAM_ERR;
    }
    uint32_t total_len = (s->msg[3] << 24) + (s->msg[2] << 16) + (s->msg[1] << 8) + s->msg[0];
    if (s->offset > total_len) {
        return COMP_PARAM_ERR;
    }
    // 计算请求crc
    for (int i = 0; i < crc_calc_len; i++) {
        req_crc_verify[i + 2] = s->data[i];
    }
    crc_result = calc_crc(req_crc_verify, crc_calc_len + 2);
    if (crc_result != crc_code) {
        return COMP_OPCODE_ERR;
    }
    return COMP_SUCCESS;
}

static void get_mock_data(slave_state *s, uint16_t comp_code)
{
    uint8_t count_num = RSP_HEAD_LEN;
    uint8_t rsp_crc_verify[256] = {MCU_ADDR, READ_FLAG, MCU_ADDR + 1};
    // completion code
    s->mock_data[1] = comp_code & 0xFF;
    s->mock_data[2] = (comp_code >> 8) & 0xFF;
    // opcode
    if (comp_code >= COMP_INNER_ERR || comp_code == COMP_SUCCESS) {
        s->mock_data[3] = s->data[3];
        s->mock_data[4] = s->data[4];
    } else {
        s->mock_data[3] = s->mock_data[4] = 0x00;
    }
    // 写操作响应数据长度为0,无数据区;命令失败无数据
    if (s->write_flag == true || comp_code != COMP_SUCCESS) {
        for (int i = 5; i < count_num; i++) {
            s->mock_data[i] = 0x00;
        }
    } else {
        // total length
        s->mock_data[5] = s->msg[0];
        s->mock_data[6] = s->msg[1];
        s->mock_data[7] = s->msg[2];
        s->mock_data[8] = s->msg[3];
        // data length
        s->mock_data[9] = s->data[9];
        s->mock_data[10] = s->data[10];
        s->mock_data[11] = s->data[11];
        s->mock_data[12] = s->data[12];
        for (int i = 4 + s->offset, j = count_num; i <  4 + s->data_length + s->offset; i++, j++) {
            s->mock_data[j] = s->msg[i];
            count_num++;
        }
    }
    s->mock_data[0] = count_num;
    for (int i = 0; i < count_num; i++) {
        rsp_crc_verify[i + 3] = s->mock_data[i];
    }
    s->mock_data[count_num] = calc_crc(rsp_crc_verify, count_num + 3);
}

static int mcu_i2cslave_tx(I2CSlave *i2c, uint8_t data)
{
    slave_state *s = MCU_I2CSLAVE(i2c);
    s->data[s->count_tx] = data;
    uint16_t ret;
    // response请求忽略
    if (s->count_tx == 1 && s->data[0] == 0x00 && s->data[1] == READ_FLAG) {
        s->count_tx++;
        return -1;
    }
    if (s->count_tx == 0 && s->buffer_flag == false) {
        ret = write_buffer(s);
        if (ret != COMP_SUCCESS) {
            get_mock_data(s, ret);
            s->count_tx++;
            return 0;
        }
    }
    // 3,4字节为opcode
    if (s->count_tx == 4) {
        s->opcode = (s->data[4] << 8) + s->data[3];
        s->key = g_strdup_printf("0x%04x", s->opcode);
        ret = cjson_read_buffer_data(s);
        g_free(s->key);
        if (ret != COMP_SUCCESS) {
            get_mock_data(s, ret);
            s->count_tx++;
            return 0;
        }
    }
    
    // 首字节数据长度+1为最后一字节
    if (s->count_tx == s->data[0] + 1) {
        ret = check_data_byte(s);
        if (ret != COMP_SUCCESS) {
            get_mock_data(s, ret);
            s->count_tx;
            return 0;
        }
        // 写操作
        if (s->write_flag == true) {
            ret = change_json_buffer(s);
            if (ret != COMP_SUCCESS) {
                get_mock_data(s, ret);
                s->count_tx;
                return 0;
            }
            // 更新json mock文件,需重新读取
            s->buffer_flag = false;
        }
        get_mock_data(s, COMP_SUCCESS);
        s->write_flag = false;
    }
    s->count_tx++;

    return 0;
}

static void mcu_i2cslave_reset(DeviceState *dev)
{
    slave_state *s = MCU_I2CSLAVE(dev);
    s->transfer_start = false;
}


static void mcu_i2cslave_realize(DeviceState *dev, Error **errp)
{
    slave_state *s = MCU_I2CSLAVE(dev);
    s->transfer_recv = false;
}

static void generic_i2cslave_access_addr(Object *obj, Visitor *v, const char *name, void *opaque, Error **errp)
{
    uint8_t *ptr = (uint8_t *)object_field_prop_ptr(obj, (Property *)opaque);
    visit_type_uint8(v, name, ptr, errp);
}

static const PropertyInfo generic_i2cslave_prop_regaddr = {
    .name  = "uint8",
    .get   = generic_i2cslave_access_addr,
    .set   = generic_i2cslave_access_addr,
};

static Property mcu_i2cslave_properties[] = {
    DEFINE_PROP_UNSIGNED_NODEFAULT("reg-id", slave_state, reg_id, generic_i2cslave_prop_regaddr, uint8_t),
    DEFINE_PROP_END_OF_LIST(),
};


static void mcu_i2cslave_class_init(ObjectClass *klass, void *data)
{
    DeviceClass *dc = DEVICE_CLASS(klass);
    I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
    k->event = mcu_i2cslave_event;
    k->recv = mcu_i2cslave_rx;
    k->send = mcu_i2cslave_tx;
    dc->reset = mcu_i2cslave_reset;
    dc->realize = mcu_i2cslave_realize;
    device_class_set_props(dc, mcu_i2cslave_properties);
}

static void mcu_i2cslave_init(Object *obj)
{
    slave_state *s = MCU_I2CSLAVE(obj);
    s->transfer_start = false;
}

static const TypeInfo mcu_i2cslave_info = {
    .name          = TYPE_MCU_I2CSLAVE,
    .parent        = TYPE_I2C_SLAVE,
    .instance_size = sizeof(slave_state),
    .class_init    = mcu_i2cslave_class_init,
    .instance_init = mcu_i2cslave_init,
};

static void mcu_i2cslave_register_types(void)
{
    type_register_static(&mcu_i2cslave_info);
}

type_init(mcu_i2cslave_register_types)